#define PUDGE_META_MONAD_SPEC BOOST_PP_ITERATION()

template
	<	class R
	,	BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,class T) >
struct monad<R (BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,T)) >
{
	typedef monad<R (BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,T))> self_type;
	typedef R result_type;

#define PUDGE_META_MONAD_M(Z,N,R) typedef T ## N t ## N ## _type;
	BOOST_PP_REPEAT(PUDGE_META_MONAD_SPEC, PUDGE_META_MONAD_M,);
#undef PUDGE_META_MONAD_M

	struct base;
	typedef std::vector<base*> list_type;
	typedef typename list_type::iterator iterator;
	list_type list_;

	struct base
	{
		virtual ~base(){}
		virtual R call
			(	BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,T)
			,	iterator
			,	iterator ) = 0;
	};

#define PUDGE_META_MONAD_M(Z,N,A) T ## N t ## N

	template<class F> struct function : base
	{
		F function_;
		function(F & f) : function_(f) {}
		template<class D> struct call_
		{
			R operator()
				(	F & f
				,	BOOST_PP_ENUM(PUDGE_META_MONAD_SPEC,PUDGE_META_MONAD_M,)
				,	iterator b
				,	iterator e ) const

			{
				D result(f(BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,t)));
				return (*++b)->call
					(	BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(PUDGE_META_MONAD_SPEC),t)
					,	result
					,	b
					,	e );
			}
		};
		template<> struct call_<R>
		{
			R operator ()
				(	F & f
				,	BOOST_PP_ENUM(PUDGE_META_MONAD_SPEC,PUDGE_META_MONAD_M,)
				,	iterator b
				,	iterator e ) const
			{
				if(b + 1 == e)
					return f(BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,t));
				R result(f(BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,t)));
				return (*++b)->call
					(	BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(PUDGE_META_MONAD_SPEC),t)
					,	result
					,	b
					,	e );
			}
		};
		virtual ~function() {}
		virtual R call
			(	BOOST_PP_ENUM(PUDGE_META_MONAD_SPEC,PUDGE_META_MONAD_M,)
			,	iterator b
			,	iterator e )
		{
			return call_<F::result<BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,T)>::type>()
				(	function_
				,	BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,t)
				,	b
				,	e );
		}
	};
	virtual ~monad()
	{
		for(list_type::iterator i = list_.begin(); i != list_.end(); ++i)
			delete *i;
	}
	template<class F> self_type & operator += (F & function_)
	{
		list_.push_back(new function<F>(function_));
		return *this;
	}
	void clear()
	{
		for(list_type::iterator i = list_.begin(); i != list_.end(); ++i)
			delete *i;
		list_.clear();
	}
	R operator ()(BOOST_PP_ENUM(PUDGE_META_MONAD_SPEC,PUDGE_META_MONAD_M,))
	{
		list_type::iterator begin (list_.begin());
		list_type::iterator end (list_.end());

		if(begin == end) throw -1;

		return (*begin)->call
			(	BOOST_PP_ENUM_PARAMS(PUDGE_META_MONAD_SPEC,t)
			, 	begin
			,	end);
	}
#undef PUDGE_META_MONAD_M
};